﻿#include "framework.h"
#include "Resource.h"
#include "FasWindow.h"
#include "MainWindow.h"

#include "commdlg.h"

#include <stdio.h>
#include <windowsx.h>

#include <gdiplus.h>
using namespace Gdiplus;


#define MAX_LOADSTRING 100



//BOOL dislog = false;



MainWindow::MainWindow(FasWindow * parent):FMainWindow(parent)
{
	LoadStringW(mInstance, IDS_APP_TITLE, mTitle, MAX_LOADSTRING);
	LoadStringW(mInstance, IDC_SIMPLENES, mWindowsClass, MAX_LOADSTRING);
	this->mStyle = WS_OVERLAPPEDWINDOW;
	this->mCsStyle = CS_HREDRAW | CS_VREDRAW;
	
	this->mUserPaint = true;

	SetMenu(IDC_SIMPLENES);
	SetIcon(IDI_GAME);
	SetClientSize(512 - 32, 480 - 32); //尺寸设置需要在菜单之后，不然不会包含菜单



}
MainWindow::~MainWindow()
{

	delete famicomThread;

}


FILE* disassemblyfile = nullptr;
int dcount = 0;

void MainWindow::Disassembly(char* line) {

}
#define TIMER_SEC 1
void MainWindow::OnCreate()
{
	d2d = new SD2D(mWnd);
	d2d->Create(
		mClientRect.right - mClientRect.left,
		mClientRect.bottom - mClientRect.top);
	famicomThread = new FamicomThread(this);
	famicomThread->Start();
	SetTimer(mWnd, TIMER_SEC, 1000, NULL);
}

wchar_t fpsstring[20] = { 0 };
D2D1_RECT_F dstrc;
D2D1_RECT_F scrrc = { 8,8,248,232 };

void MainWindow::CalcSize()
{
	float scale = 1;
	if (d2d->targetWidth < d2d->targetHeight)
	{
		scale = (float)d2d->targetWidth / 240.f;
	}
	else {
		scale = (float)d2d->targetHeight / 224.f;
	}

	int newwidth = (int)(240.f * scale);
	int newheight = (int)(224.f * scale);

	dstrc.left = (d2d->targetWidth - newwidth) / 2;
	dstrc.top = (d2d->targetHeight - newheight) / 2;
	dstrc.right = dstrc.left + newwidth;
	dstrc.bottom = dstrc.top + newheight;
}
void MainWindow::OnPaint(PaintEvent* paintEvent)
{
	
	if (recreate)
	{
		RECT rc;
		GetClientRect(mWnd, &rc);
		d2d->ReCreate(rc.right - rc.left, rc.bottom - rc.top);

		//重新计算尺寸
		this->CalcSize();

		recreate = false;
	}

	famicomThread->GetFrameBuffer(mFrameMem, sizeof(mFrameMem));
	this->Render(mFrameMem);
	d2d->swapChain->Present(1, 0);
}

void MainWindow::Render(int* gameframe) {
	int size = 256 * 240;

	d2d->buffer->CopyFromMemory(nullptr, gameframe, 256 * 4);

	d2d->context->BeginDraw();

	d2d->context->Clear(0);
	d2d->context->DrawBitmap(d2d->buffer,
		&dstrc,
		1.f,
		D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
		//D2D1_INTERPOLATION_MODE_ANISOTROPIC,
		&scrrc
	);

	static D2D1_RECT_F textLayoutRect = D2D1::RectF(
		8,
		8,
		200,
		8
	);

	d2d->context->DrawText(
		fpsstring,           // Text to render
		wcslen(fpsstring),       // Text length
		d2d->textFormat,     // Text format
		textLayoutRect,    // The region of the window where the text will be rendered
		d2d->primaryBrush      // The brush used to draw the text
	);
	DX::ThrowIfFailed(d2d->context->EndDraw());
}

bool MainWindow::OnKeyUp(unsigned int keyCode)
{
	int i;
	for (i = 0; i < 16; i++)
	{
		if (keyCode == mKeyMap[i])
		{
			famicomThread->Input(i, 0);
			return false;
		}
	}
	if (keyCode == '1')
	{
		famicomThread->Save();
	}
	else if (keyCode == '2')
	{
		famicomThread->Restore();
	}
	return true;
}

bool MainWindow::OnKeyDown(unsigned int keyCode)
{
	int i;
	for (i = 0; i < 16; i++)
	{
		if (keyCode == mKeyMap[i])
		{
			famicomThread->Input(i, 1);
			return false;
		}
	}
	return true;
}

void MainWindow::OnResize()
{
	this->recreate = true;
}

void MainWindow::OnDestroy()
{
	famicomThread->TryStop();
	famicomThread->Wait();
	delete d2d;
}

void  MainWindow::TarckMouse()
{
	if (!mMouseTrack) {
		TRACKMOUSEEVENT track;
		track.cbSize = sizeof(track);
		track.dwFlags = TME_LEAVE | TME_HOVER;
		track.dwHoverTime = 6000;
		track.hwndTrack = mWnd;
		::TrackMouseEvent(&track);
		mMouseTrack = true;
	}
}
void  MainWindow::OnMouseMove(int x, int y)
{
	TarckMouse();
	//移动距离大于4个像素才显示鼠标
	if (mMouseHide) {
		if (abs(mMouseHoverPoint_x - x) > 4
			|| abs(mMouseHoverPoint_y - y) > 4) {
			mMouseHide = false;
			::ShowCursor(true);
		}
	}
}

LRESULT MainWindow::Dispatch(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_ERASEBKGND:
		return true;
	case WM_COMMAND:
		return this->OnCommand(wParam, lParam);
		break;
	case WM_NCLBUTTONDOWN:
		break;
	case WM_NCLBUTTONUP:
		break;
	case WM_ACTIVATE:
		if (famicomThread != nullptr)
		{
			//判断当前窗口时候失去激活
			if (LOWORD(wParam) == WA_INACTIVE)
			{
				mActivited = false;
				famicomThread->Pause();
			}
			else {
				TarckMouse();
				mActivited = true;
				famicomThread->Play();
			}
		}
		break;
	case WM_MOUSELEAVE:
		if (mMouseHide) {
			mMouseHide = false;
			::ShowCursor(true);
		}
		mMouseTrack = false;
		break;
	case WM_MOUSEHOVER:
		if (!mMouseHide) {
			mMouseHide = true;
			mMouseHoverPoint_x = GET_X_LPARAM(lParam);
			mMouseHoverPoint_y = GET_Y_LPARAM(lParam);
			::ShowCursor(false);
		}
		mMouseTrack = false;
		break;
	case WM_TIMER: {
		if (wParam == TIMER_SEC) {
			//每秒更新一次FPS
			int fps = famicomThread->FPS;
			int fpsf = (int)(famicomThread->FPS * 100) % 100;
			wsprintf(fpsstring, L"FPS:%d.%d", fps, fpsf);
		}
		return 0;
	}
	default:
		break;
	}

	return FMainWindow::Dispatch(message, wParam, lParam);
}

bool MainWindow::OnCommand(WPARAM wParam, LPARAM lParam)
{
	int wmId = LOWORD(wParam);
	switch (wmId)
	{
	case ID_OPENFILE: {

		OPENFILENAME opfn;
		WCHAR strFilename[MAX_PATH];//存放文件名  
		//初始化  
		ZeroMemory(&opfn, sizeof(OPENFILENAME));
		opfn.lStructSize = sizeof(OPENFILENAME);//结构体大小  
		//设置过滤  
		opfn.lpstrFilter = L"nes文件\0*.nes";
		//默认过滤器索引设为1  
		opfn.nFilterIndex = 1;
		//文件名的字段必须先把第一个字符设为 \0  
		opfn.lpstrFile = strFilename;
		opfn.lpstrFile[0] = '\0';
		opfn.nMaxFile = sizeof(strFilename);
		//设置标志位，检查目录或文件是否存在  
		opfn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
		if (GetOpenFileName(&opfn))
		{
			famicomThread->SyncLoadRom(strFilename);
		}
		break;
	}
	default:
		return true;
		break;
	}
	return false;
}
